Traverse a Square - Part 3 - Loops

Compared to the original programme, the programme that contains the variables is easier to modify. But it still contains a lot of repetition.

Let's remind ourselves of it:

import time

side_length_time=1
turn_speed=1.8
turn_time=0.45

#side 1
robot.move_forward()
time.sleep(side_length_time)
#turn 1
robot.rotate_left(turn_speed)
time.sleep(turn_time)
#side 2
robot.move_forward()
time.sleep(side_length_time)
#turn 2
robot.rotate_left(turn_speed)
time.sleep(turn_time)
#side 3
robot.move_forward()
time.sleep(side_length_time)
#turn 3
robot.rotate_left(turn_speed)
time.sleep(turn_time)
#side 4
robot.move_forward()
time.sleep(side_length_time)

One of the principles of good computer programming is often referred to using the acronym DRY, which stands for Don't Repeat Yourself.

So what bits of repetition can you see in our simple square traversing program?

I think the following block of code repeats:

#side
robot.move_forward()
time.sleep(side_length_time)
#turn
robot.rotate_left(turn_speed)
time.sleep(turn_time)

So how can we get out programme to repeat that block of code the required number of times?

Introducing the for loop

In common with many programming languages, Python supports a construct known as a for loop. This provides a means to repeat a block of code a required number of times.

The loop construction can be illustrated by running the following code cell:


In [ ]:
for count in range(0,3):
    print(count)
    
print("And the final value of `count` is", count)

Let's pick that apart.

First, consider the range(0,3) statement.

The range(M, N) statement creates a so-called iterator that returns a sequence of numbers in the range M to N-1 in sequence, one number each time the statement is called.

(In fact, we could use a simpler range() statement, range(N), which by default iterates through numbers on the range 0..N-1.)

The for statement is a construct that will repeated 'pull out' each element from an iterator one item at a time, pass, setting a variable (in the above case, count) to the extracted value on each pass, and then running the code block "contained" in the loop.

Containment in the loop is indicated by indenting lines of code immediately following the the for statement.

Using a for loop, do you think you could write a program that drives the robot around a square and that only requires you to state the "traverse side" and "turn" actions once?

Load in the set up requirements, and then have a go at writing the programme.


In [ ]:
%run 'Set-up.ipynb'
%run 'Loading scenes.ipynb'
%run 'vrep_models/PioneerP3DX.ipynb'

In [ ]:
%%vrepsim '../scenes/OU_Pioneer.ttt' PioneerP3DX
import time

#Your code here

How did you get on?

You can see my attempt below - note how I set the variable outside the loop so they are only set once.

Also note how I abstracted out the number of sides into a variable and added a variable to allow me to set the speed of moving along the side.


In [ ]:
%%vrepsim '../scenes/OU_Pioneer.ttt' PioneerP3DX
import time

side_speed=2
side_length_time=1
turn_speed=1.8
turn_time=0.45

number_of_sides=4

for sides in range(0,number_of_sides):
    #side
    robot.move_forward(side_speed)
    time.sleep(side_length_time)
    #turn
    robot.rotate_left(turn_speed)
    time.sleep(turn_time)
    
#We could put additional code here
#This code would execute once the for loop has completely finished

There's Often Another Way - The while Loop

One of the joys - or maybe it's frustrations?! - of writing computer programmes is that there are often multiple ways of achieving the same effect.

For example, as an alternative to using a for loop, we could use another loop construct, the while loop.

The while loop is a conditional statement that starts by checking the truth or falsity of a condition; if that condition evaluates as "true", the while loop executes the code that is contained within it, otherwise the programme continues by executing the next statement after the while block.

If the while loop executes the code contained within it, once that code has finshed executing the while loop checks the state of the condition again, and the process repeats.

So what is a logical, or Boolean, condition?

Conditions and Conditional Statements

Boolean or logical conditions are logical statements that evaluate as a Boolean True or False value. Conditional statements are statements that test a logical condition and then make a decision as what to do next on based on whether the condition evaluates as True or False.

In it's simplest form, we can use a while statement to create an infinite loop by explicitly setting the tested condition to be True.

while True:
    #an infinite loop
    #The pass statement is a null statement ("do nothing")
    pass

This loop that will execute the contained code block indefinitely (an infinite number of times). In the above case, the programme will do nothing, forever.

You can stop an infinite loop running in a code cell by pressing the Stop button on the notebook toolbar.

For example, run the following while loop and then stop it:


In [ ]:
count=0

while True:
    count=count+1
    
count

You may have noticed that the value of count, the final line of the cell, is not displayed.

This is because the programme never gets that far. When you stop the code executing, you stop it whilst it is still inside the while loop.

Check the count value to see how many times the while loop iterated round:


In [ ]:
count

Rather than looping an infinite number of times, we could test a condition based on how many times we have already been round the loop.

In a code cell, explore the Boolean nature of the following examples, one at a time, or use ones of your own devising:

#Inequality tests
4 > 3
5 < 2
5 >= 3
print(3 <= 2)

#We can test variables
apples=1
pears=2

apples > pears
apples + 1 == pears

#Equality tests - this is not "double assignment"
1==1
1==2
apples==1

#And "not equal" tests...
4 != 5
4 != 4

#Integer numbers have a truth value: 0 is False, others are true

1==True
0==False
True==False
1==False

In [ ]:
#Test some Boolean conditions, one at a time

Using a conditional test based on testing a count variable that increments each time a while loop loops round, see if you can use a while loop to count up from 1 to 4, displaying the count each time round the loop using a print() statement.

If the while loop looks like it's stuck in an infinite loop, stop it executing using the stop button in the notebook toolbar.


In [ ]:
#Use a while loop to print out a count going from 1 to 4

How did you do?

Here's one way of doing it:

count=1
while count<=4:
    print(count)

Now see if you can use a while loop to get our simulated robot to trace out a square.


In [ ]:
%%vrepsim '../scenes/OU_Pioneer.ttt' PioneerP3DX
import time

Using break

If the condition tested by the while loop evaluates as False, the programme moves on to the next statement, if any, after the while block.

However, we can also break out of the while loop using another sort of conditional statement, the if statement, and invoking the break command, which moves the programme flow out of the while loop and onto the next statement, if any, after the while block.


In [ ]:
count=1

#Looks like an infinite loop...
while True:
    print(count)
    #but with a break out clause
    if count==4:
        break
    count = count+1

See if you can use this form of loop to get the simulated robot to traverse a square.

As you write your program, try to remember not to repeat yourself...


In [ ]:
%%vrepsim '../scenes/OU_Pioneer.ttt' PioneerP3DX
import time

How did you get on?

You may have found that your robot traced out only three sides, or maybe it did five sides, rather than the required four sides.

Check the logic of your programme if so:

  • what was the original value of the counter?
  • where did you place the conditional test? Sometimes it can be clearer to test at the start of the block, sometimes it can be clearer to test at the end of the block.
  • where in your programme did you change the counter relative to the conditional test of it?

Here's what my code looked like - it's a little perverse in that it counts down, rather than up:

import time

side_speed=2
side_length_time=1
turn_speed=1.8
turn_time=0.45

number_of_sides_to_do=4

while True:

    print("Starting side", (4 - number_of_sides_to_do) + 1)

    #side
    robot.move_forward(side_speed)
    time.sleep(side_length_time)

    #turn
    robot.rotate_left(turn_speed)
    time.sleep(turn_time)

    number_of_sides_to_do=number_of_sides_to_do - 1
    print("Sides still to do:",number_of_sides_to_do)

    if number_of_sides_to_do==0:
        break

So, that's loops and conditional statements.

It's been a busy notebook, concept-wise, packed full of computational programming ideas. In particular:

  • the use of iterators, such as the range() function, that can return a series of incrementing values within a particular range when used in conjuction with a for statement;
  • a for loop, that repeatedly requests one from a series of items represented as an interator. The loop executes the code contained within it the same number of times as there are items represented by the iterator. The value of each item retrieved from the iterator is assigned to a variable that can be used within the for loop.
  • Boolean condition statements that can evaluate as True or False.
  • a while loop, that tests a condition and runs the code block contained within it if the condition evaluates True, passing on to the first line of code after the while block, if there is one.
  • a conditional if statement that tests a condition and executes a contained code block if the condition evaluates True.
  • a break statement that can be used inside a while block to escape from it and pass control to the first line of code after the while block, if there is one. This can be used in association with a conditional if statement to break out of a while loop if a condition is met within it.

As far as Big Ideas in programming go, you've now been introduced to many of them.